package com.yn.xgame.game;

import com.google.common.collect.ImmutableMap;
import com.yn.xgame.*;
import com.yn.xgame.game.benz.GameBenzTable;
import com.yn.xgame.game.benz.RoomBenzPlayer;
import com.yn.xgame.game.fish.FishTable;
import com.yn.xgame.game.message.CommonGameStartNotice;
import com.yn.xgame.game.message.GameJoinTable;
import com.yn.xgame.game.message.GameStart;
import com.yn.xgame.game.message.PlayerLeave;
import com.yn.xgame.message.C2GPbRedirectMessage;
import com.yn.xgame.message.MqBeanMessage;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * GameServer
 * Created by wangboo on 17/7/18.
 */
public class GameServer extends ThreadServer {

    private static final Logger logger = LoggerFactory.getLogger(GameServer.class);

    private static Map<String, Map<String, IGameTable>> gameMap;
    private static Map<Long, IGameTable> sessionMap;

    public GameServer() {
        super("Game" + GameApp.config.getId());
        gameMap = new HashMap<>();
        sessionMap = new HashMap<>();
        GameApp.config.getGameNameList().forEach(name -> gameMap.put(name, new HashMap<>()));
        gameMap = ImmutableMap.copyOf(gameMap);
        useTimerManager();
    }

    @Override
    public boolean handleMessage(IMessage message) {
        if (super.handleMessage(message)) {
            return true;
        }
        if (message instanceof MqBeanMessage) {
            MqBeanMessage mqMsg = (MqBeanMessage) message;
            switch (mqMsg.getMsgId()) {
                case MqMsgId.gc2g_start_game:
                    onGameStart(mqMsg, (GameStart) mqMsg.getBean());
                    break;
                case MqMsgId.common_player_leave:
                    handlePlayerLeave((PlayerLeave) mqMsg.getBean());
                    break;
                case MqMsgId.gc2g_game_join_game:
                    handleJoinGame(mqMsg, (GameJoinTable) mqMsg.getBean());
                    break;
            }
        } else if (message instanceof C2GPbRedirectMessage) {
            C2GPbRedirectMessage pbMsg = (C2GPbRedirectMessage) message;
            switch (pbMsg.getPb().getMsgid()) {
                case C2G_FishCreate:
                    handleFishCreate(pbMsg);
                    break;
                case C2G_FishDeath:
                    handleFishDeath(pbMsg);
                    break;
                case C2G_FishBullet:
                    handleFishBullet(pbMsg);
                    break;
            }
        }
        return false;
    }

    // 中途加入游戏
    private void handleJoinGame(MqBeanMessage mqMsg, GameJoinTable bean) {
        Map<String, IGameTable> tableMap = gameMap.get(bean.game);
        XAssert.nonNull(tableMap, bean.game);
        IGameTable table = tableMap.get(bean.tableId);
        XAssert.nonNull(table, bean.tableId, bean.game);
        table.handleJoin(bean.player);
        String fromTopic = mqMsg.getToTopic();
        String gcTopic = mqMsg.getFromTopic();
        sessionMap.put(bean.player.sid, table);
        CommonGameStartNotice notice = new CommonGameStartNotice(mqMsg.getFromTopic(), bean.game, mqMsg.getToTopic(),
                table.getRoomId(), table.getTableId(), bean.player.userId);
        GameApp.mqClient.sendInter(fromTopic, gcTopic, MqMsgId.common_player_game_start_notice,
                notice);
        GameApp.mqClient.sendInter(fromTopic, bean.player.logicTopic, MqMsgId.common_player_game_start_notice,
                notice);
    }

    private void handlePlayerLeave(PlayerLeave leave) {
        IGameTable table = sessionMap.remove(leave.sessionId);
        if (table == null) return;
        table.handlePlayerLeave(leave);
        if (table.getPlayerSize() == 0) {
            // 房间没人了
            table.handleStop();
            gameMap.get(leave.game).remove(table.getTableId());
        }
    }

    private void handleFishBullet(C2GPbRedirectMessage pbMsg) {
        FishTable table = (FishTable) sessionMap.get(pbMsg.getSessionId());
        table.handleFishBullet(pbMsg.getSessionId(), pbMsg.getPb().getFishBullet());
    }

    private void handleFishDeath(C2GPbRedirectMessage pbMsg) {
        FishTable table = (FishTable) sessionMap.get(pbMsg.getSessionId());
        table.handleFishDeath(pbMsg.getSessionId(), pbMsg.getPb().getFishDeath());
    }

    private void handleFishCreate(C2GPbRedirectMessage pbMsg) {
        FishTable table = (FishTable) sessionMap.get(pbMsg.getSessionId());
        table.handleFishCreate(pbMsg.getSessionId(), pbMsg.getPb().getFishCreate());
    }

    private void onGameStart(MqBeanMessage mqMsg, GameStart bean) {
        Map<String, IGameTable> map = gameMap.get(bean.game);
        XAssert.nonNull(map, bean.game);
//        if (rateMap == null) {
//            logger.error("this GameServer do not has game: {}, sub gameTopic: {}, GameNames: {}",
//                    bean.game, GameApp.config.getTopicList(), GameApp.config.getGameNameList());
//            // 给GameCenter回复，开始游戏失败
//            GameApp.mqClient.sendInter(mqMsg.getToTopic(), mqMsg.getFromTopic(),
//                    MqMsgId.game_start_game_resp, ImmutableMap.of("tid", bean.tableId, "result", 1));
//            return;
//        }
        // 房间编号存在
        XAssert.isFalse(map.containsKey(bean.tableId), bean.tableId);
        // 设置gameTopic
        bean.list.forEach(p -> p.gameTopic = mqMsg.getToTopic());
        IGameTable table;
        switch (bean.game) {
            case "benz":
                table = handleCreateRoomBenz(bean);
                break;
            case GlobalSetting.GAME_FISH:
                table = handleCreateTableFish(mqMsg, bean);
                break;
            default:
                throw new RuntimeException("unknown game: " + bean.game);
        }
        bean.list.forEach(p -> sessionMap.put(p.sid, table));
        table.handleStart();
        map.put(bean.tableId, table);
        String myTopic = mqMsg.getToTopic();
        String gcTopic = mqMsg.getFromTopic();
        // 给gc和logic回复，已经在游戏中
        // String center, String game, int roomId, String tableId, int userId
        CommonGameStartNotice notice = new CommonGameStartNotice(mqMsg.getFromTopic(), bean.game, myTopic,
                bean.type, table.getTableId(), 0);
        bean.list.forEach(p -> {
            notice.userId = p.userId;
            // 创建成功消息发送到的logic
            GameApp.mqClient.sendInter(myTopic, p.logicTopic, MqMsgId.common_player_game_start_notice,
                    notice);
        });
        // 创建成功消息发送到的 game center, gc 只用发一次
        GameApp.mqClient.sendInter(myTopic, gcTopic, MqMsgId.common_player_game_start_notice,
                notice);
    }

    private IGameTable handleCreateTableFish(MqBeanMessage mqMsg, GameStart req) {
        return new FishTable(mqMsg.getToTopic(), req.tableId, req.type, req.hostIdx, req.list);
    }

    private IGameTable handleCreateRoomBenz(GameStart bean) {
        List<RoomBenzPlayer> list = bean.list.stream().map(RoomBenzPlayer::new).collect(Collectors.toList());
        return new GameBenzTable(bean.tableId, bean.type, bean.tableId, list);
    }
}
